<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>陷阱</title>
    <script src="js/traceur.js"></script>
    <script src="js/bootstrap.js"></script>
    <script type="module">

        //get(target，property，receiver)方法:在目标对象中查找属性
        var proxy = new Proxy({
                age: 12
            }, {
                get: function (target, property, receiver) {
                    if (property in target) {
                        return target[property];
                    } else {
                        return "Not Found";
                    }
                }
            }
        );
        console.log(Reflect.get(proxy, "age"));  // 12
        console.log(Reflect.get(proxy, "name")); // Not Found

        //receiver属性
        var proxy = new Proxy({age: 13}, {
                get: function (target, property, receiver) {
                    //{age: 13},当访问属性不存在时，输出receiver时进行死循环
                    //console.log(receiver);
                    if (property in target) {
                        //console.log(receiver);
                        return target[property];
                    } else {
                        return "Not Found";
                    }
                }
            }
        );
        var temp = proxy.age;
        var obj = {
            age: 12,
            //将代理对象加入到__proto__
            __proto__: proxy
        }
        temp = obj.name; //在代理对象查找name属性，返回"Not Found"

        //set()方法：设置属性的值
        var proxy = new Proxy({}, {
            set: function (target, property, value, receiver) {
                target[property] = value;
                return true;
            }
        });
        Reflect.set(proxy, "name", "Eden");
        console.log(proxy.name); // "Eden

        //has()方法：使用in运算符检查属性是否存在时，将执行陷阱
        var proxy = new Proxy({age: 12}, {
            has: function (target, property) {
                if (property in target) {
                    return true;
                } else {
                    return false;
                }
            }
        });
        console.log(Reflect.has(proxy, "name")); //false
        console.log(Reflect.has(proxy, "age"));  // true

        //isExtensible（）方法检查对象是否可扩展
        var proxy = new Proxy({age: 12}, {
            isExtensible: function (target) {
                return Object.isExtensible(target);
            }
        });
        console.log(Reflect.isExtensible(proxy)); // "true"

        //getPrototypeOf()方法:检索内部[[prototype]]属性的值时，执行getPrototypeOf陷阱
        var proxy = new Proxy({age: 12, __proto__: {name: "Eden"}}, {
            getPrototypeOf: function (target) {
                return Object.getPrototypeOf(target);
            }
        });
        console.log(Reflect.getPrototypeOf(proxy).name); // "Eden"

        //设置内部[[prototype]]属性的值时，执行setPrototypeOf陷阱
        var proxy = new Proxy({}, {
            setPrototypeOf: function (target, value) {
                Reflect.setPrototypeOf(target, value);
                return true;
            }
        });
        Reflect.setPrototypeOf(proxy, {name: "Eden"});
        console.log(Reflect.getPrototypeOf(proxy).name); // "Eden"

        //使用Object.preventExtensions()方法阻止添加新属性时，将执行preventExtensions陷阱
        //        var proxy = new Proxy({}, {
        //            preventExtensions: function(target){
        //                Object.preventExtensions(target);
        //                return true;
        //            }
        //        });
        //        Reflect.preventExtensions(proxy);
        //        proxy.a = 12;
        //        console.log(proxy.a); // TypeError: Cannot define property:a, object is not extensible.


        //使用Object.getOwnPropertyDescriptor()方法检索属性的描述符时，执行getOwnPropertyDescriptor陷阱。
        var proxy = new Proxy({age: 12}, {
            getOwnPropertyDescriptor: function (target, property) {
                return Object.getOwnPropertyDescriptor(target, property);
            }
        });
        var descriptor = Reflect.getOwnPropertyDescriptor(proxy, "age");
        console.log("Enumerable: " + descriptor.enumerable); // Enumerable: true
        console.log("Writable: " + descriptor.writable); // Writable: true
        console.log("Configurable: " + descriptor.configurable); // Configurable: true
        console.log("Value: " + descriptor.value); // Value: 12


        //使用Object.defineProperty()方法定义属性时，会执行defineProperty陷阱
        var proxy = new Proxy({}, {
            defineProperty: function (target, property, descriptor) {
                Object.defineProperty(target, property, descriptor);
                return true;
            }
        });
        Reflect.defineProperty(proxy, "name", {value: "Eden"});
        console.log(proxy.name); // "Eden"


        //使用delete操作符或Reflect.deleteProperty()方法删除属性时，执行deleteProperty陷阱
        var proxy = new Proxy({age: 12}, {
            deleteProperty: function (target, property) {
                return delete target[property];
            }
        });
        Reflect.deleteProperty(proxy, "age");
        console.log(proxy.age); // "undefined"

        //使用for ... in循环或Reflect.enumerate（）方法循环使用属性键时，执行枚举陷阱
        //enumerate方法已经被取消
        //        var proxy = new Proxy({age: 12, name: "Eden"}, {
        //            enumerate: function(target){
        //                var arr = [];
        //                for(var p in target) {
        //                    arr[arr.length] = p;
        //                }
        //                return arr[Symbol.iterator]();
        //            }
        //        });
        //        var iterator = Reflect.enumerate(proxy);
        //        console.log(iterator.next().value);
        //        console.log(iterator.next().value);
        //        console.log(iterator.next().done);

        //检索自己的属性键时，执行ownKeys陷阱
        var s = Symbol();
        var object = {age: 12, __proto__: {name: "Eden"}, [s]: "Symbol"};
        Object.defineProperty(object, "profession", {
            enumerable: false,
            configurable: false,
            writable: false,
            value: "Developer"
        })
        var proxy = new Proxy(object, {
            ownKeys: function (target) {
                return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target));
            }
        });
        console.log(Reflect.ownKeys(proxy)); // ["age", "profession", Symbol()]
        console.log(Object.getOwnPropertyNames(proxy)); // ["age", "profession"]
        console.log(Object.keys(proxy)); // ["age"]
        console.log(Object.getOwnPropertySymbols(proxy)); // [Symbol()]

        //函数的apply()和call()方法以及Reflect.apply()方法也执行apply trap
        //在apply()代理方法中，第三参数不能设置默认的arguments，否则报错。
        var proxy = new Proxy(function () {
        }, {
            apply: function (target, thisValue, arguments1) {
                console.log(thisValue.name);  // Eden
                return arguments1[0] + arguments1[1] + arguments1[2];
            }
        });
        var obj = {
            name: "Eden",
            f: proxy
        }
        var sum = obj.f(1, 2, 3);
        console.log(sum); //6

        //使用new运算符或者Reflect.construct()方法来调用目标作为构造函数将执行Construct陷阱。
        var proxy = new Proxy(function () {
        }, {
            construct: function (target, arguments1) {
                return {name: arguments1[0]};
            }
        });
        var obj = new proxy("Eden");  //在这里创建 name属性
        console.log(obj.name); //"Eden"

        //撤销的代理被撤销
        //创建revocable(可撤销)的代理，我们必须使用Proxy.revocable()方法
        var revocableProxy = Proxy.revocable({
                age: 12
            }, {
                get: function (target, property, receiver) {
                    if (property in target) {
                        return target[property];
                    } else {
                        return "Not Found";
                    }
                }
            }
        );
        console.log(revocableProxy.proxy.age); //12
        revocableProxy.revoke(); // 撤消所有属性
        console.log(revocableProxy.proxy.name); // TypeError: proxy is revoked

    </script>
</head>
<body>

</body>
</html>